using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

// required for DLLImport
using System.Runtime.InteropServices;

using FT_HANDLE = System.UInt32;

namespace SMD2XX
{

    #region type definitions
    // enum used for the various possible returns from the D2XX function calls
    public enum FT_STATUS
    {
        FT_OK = 0,
        FT_INVALID_HANDLE,
        FT_DEVICE_NOT_FOUND,
        FT_DEVICE_NOT_OPENED,
        FT_IO_ERROR,
        FT_INSUFFICIENT_RESOURCES,
        FT_INVALID_PARAMETER,
        FT_INVALID_BAUD_RATE,
        FT_DEVICE_NOT_OPENED_FOR_ERASE,
        FT_DEVICE_NOT_OPENED_FOR_WRITE,
        FT_FAILED_TO_WRITE_DEVICE,
        FT_EEPROM_READ_FAILED,
        FT_EEPROM_WRITE_FAILED,
        FT_EEPROM_ERASE_FAILED,
        FT_EEPROM_NOT_PRESENT,
        FT_EEPROM_NOT_PROGRAMMED,
        FT_INVALID_ARGS,
        FT_OTHER_ERROR
    };
    #endregion


    class SM_D2XX
    {

    #region DLL declarations

        #region Open and Close

        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_Open(UInt32 uiDevice, ref UInt32 ftHandle);

        // Two overload versions for FT_OpenEX
        // Flags = 1 opens by serial number
        // Flags = 2 opens by description
        // Flags = 3 opens by Location Id
        // needed two overloads so that we can send either a string or a UInt32

        // open by serial number or description string
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_OpenEx([MarshalAs(UnmanagedType.LPStr)] string str, UInt32 Flags, ref UInt32 ftHandle);
        
        // open by Location ID
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_OpenEx(UInt32 locID, UInt32 Flags, ref UInt32 ftHandle);
        
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_Close(UInt32 ftHandle);

        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_ResetDevice(UInt32 ftHandle);

        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_CyclePort(UInt32 ftHandle);

        #endregion

        #region Device Information
        // Import some of the FTDI D2XX.DLL functions with C# compatible parameters
        // Create a C# friendly port for each function

        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_CreateDeviceInfoList(ref UInt32 NumDevs);

        [DllImport("FTD2XX.dll")]
        static extern  FT_STATUS FT_GetDeviceInfoDetail(UInt32 Index,ref UInt32 lpdwFlags,ref UInt32 lpdwType,ref UInt32 lpdwID,ref UInt32 lpdwLocId,[MarshalAs(UnmanagedType.LPArray)] byte[] serialNumberArray,[MarshalAs(UnmanagedType.LPArray)] byte[] descriptionArray,ref UInt32 ftHandle);
        
        // NOTE: set pwDummy to NULL when calling this function 
        [DllImport("FTD2XX.dll")]
        static extern  FT_STATUS FT_GetDeviceInfo(UInt32 ftHandle,ref UInt32 lpdwType,ref UInt32 lpdwID,[MarshalAs(UnmanagedType.LPArray)] byte[] serialNumberArray,[MarshalAs(UnmanagedType.LPArray)] byte[] descriptionArray,UInt32 pwDummy);

        #endregion

        #region EEPROM
        //EE_Read - not used since EE_ReadEx does the same and is more C# friendly
        //EE_Program - not used since EE_ProgramEx does the same and is more C# friendly

        //EE_ReadEx
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_EE_ReadEx(UInt32 ftHandle, ref ft_program_data_struct lpData, [MarshalAs(UnmanagedType.LPArray)] byte[] Manufacturer, [MarshalAs(UnmanagedType.LPArray)] byte[] Manufacturerid, [MarshalAs(UnmanagedType.LPArray)] byte[] Description, [MarshalAs(UnmanagedType.LPArray)] byte[] SerialNumber);

        //EE_ProgramEx - TODO - test
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_EE_ProgramEx(FT_HANDLE ftHandle, ref ft_program_data_struct lpData, [MarshalAs(UnmanagedType.LPArray)] byte[] Manufacturer, [MarshalAs(UnmanagedType.LPArray)] byte[] Manufacturerid, [MarshalAs(UnmanagedType.LPArray)] byte[] Description, [MarshalAs(UnmanagedType.LPArray)] byte[] SerialNumber);
        
        //EraseEE - NOT IMPLEMENTED SINCE IT COULD SET VID TO 0 AND KILL THE DEVICE

        //EE_UARead
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_EE_UARead(UInt32 ftHandle, [Out] char[] EEUAData, UInt32 DataLen, ref UInt32 BytesRead);

        //EE_UAWrite
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_EE_UAWrite(UInt32 ftHandle, char[] EEUAData, UInt32 DataLen);

        //EE_UASize
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_EE_UASize(UInt32 ftHandle, ref UInt32 EEUA_Size);

        #endregion

        #region Bit Banging
        // GetBitMode
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_GetBitMode(FT_HANDLE ftHandle, ref byte pucMode);

        // SetBitMode
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_SetBitMode(FT_HANDLE ftHandle, byte ucMask, byte ucEnable);
        #endregion

        #region Read and write data

        //Read
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_Read(FT_HANDLE ftHandle, ref byte lpBuffer, UInt32 dwBytesToRead, ref UInt32 lpdwBytesReturned);

        //Write
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_Write(FT_HANDLE ftHandle, ref byte lpBuffer, UInt32 dwBytesToWrite, ref UInt32 lpdwBytesWritten);

        #endregion

        #region Set Serial properties

        // SetBaudRate
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_SetBaudRate(UInt32 ftHandle, UInt32 dwBaudRate);

        // SetDataCharacteristics
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_SetDataCharacteristics(FT_HANDLE ftHandle, byte uWordLength, byte uStopBits, byte uParity);

        // SetFlowControl
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_SetFlowControl(FT_HANDLE ftHandle, char usFlowControl, byte uXon, byte uXoff);

        // SetDtr
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_SetDtr(FT_HANDLE ftHandle);

        // ClrDtr
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_ClrDtr(FT_HANDLE ftHandle);

        // SetRts      
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_SetRts(FT_HANDLE ftHandle);

        // ClrRts
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_ClrRts(FT_HANDLE ftHandle);

        // GetModemStatus
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_GetModemStatus(FT_HANDLE ftHandle, ref UInt32 lpdwModemStatus);
        
        // SetChars
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_SetChars(FT_HANDLE ftHandle, byte uEventCh, byte uEventChEn, byte uErrorCh, byte uErrorChEn);

        // Purge
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_Purge(FT_HANDLE ftHandle, UInt32 dwMask);

        // SetTimeouts
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_SetTimeouts(UInt32 ftHandle, UInt32 dwReadTimeout, UInt32 dwWriteTimeout);

        // GetQueueStatus
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_GetQueueStatus(UInt32 ftHandle, ref UInt32 lpdwAmountInRxQueue);

        // GetStatus
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_GetStatus(UInt32 ftHandle, ref UInt32 lpdwAmountInRxQueue, ref UInt32 lpdwAmountInTxQueue, ref UInt32 lpdwEventStatus);

        // SetBreakOn
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_SetBreakOn(FT_HANDLE ftHandle);

        // SetBreakOff
        [DllImport("FTD2XX.dll")]
        static extern FT_STATUS FT_SetBreakOff(FT_HANDLE ftHandle);
 
        #endregion

    #endregion

    #region Data Accessors

        #region Device Information Accessors

        // Keep the serial number and description arrays private and expose the data as a 
        // string. Since the D2XX dll requires that the serial number and the description
        // be in byte arrays, we have to jump through some hoops for use with C#

        private byte[] manufacturerArray = new Byte[16];
        public string Manufacturer
        {
            get
            {
                string temp = "";
                foreach (char c in manufacturerArray) temp += c;
                return temp;
            }
        }

        private byte[] manufacturerIDArray = new Byte[16];
        public string ManufacturerID
        {
            get
            {
                string temp = "";
                foreach (char c in manufacturerIDArray) temp += c;
                return temp;
            }
        }         
        
        private Byte[] serialNumberArray = new Byte[64];
        public string SerialNumber
        {
            get
            {
                string temp = "";
                for (int i = 0; i < 16; i++) {
                    if (serialNumberArray[i] == 0) break;
                    temp += Convert.ToChar(serialNumberArray[i]);
                }
                return temp;
            }
        }

        private byte[] descriptionArray = new Byte[64];
        public string Description
        {
            get
            {
                string temp = "";
                for (int i = 0; i < 16; i++)
                {
                    if (descriptionArray[i] == 0) break;
                    temp += Convert.ToChar(descriptionArray[i]);
                }
               return temp;
            }
        }

        // the rest of the accessors are for UInt32
        private static UInt32 index_p;
        public UInt32 Index { get { return index_p; } set { index_p = value; } }
        private UInt32 flags_p;
        public UInt32 Flags { get { return flags_p; } set { flags_p = value; } }
        private UInt32 type_p;
        public UInt32 Type { get { return type_p; } set { type_p = value; } }
        private UInt32 devicetype_p;
        public UInt32 DeviceType { get { return devicetype_p; } set { devicetype_p = value; } }
        private UInt32 locID_p;
        public UInt32 LocID { get { return locID_p; } set { locID_p = value; } }
        private UInt32 handle_p;
        public UInt32 Handle { get { return handle_p; } set { handle_p = value; } }
        private UInt32 numDevs_p;
        public UInt32 NumDevs { get { return numDevs_p; } set { numDevs_p = value; } }
        //private UInt32 devicenumber;
        //public UInt32 DeviceNumber { get { return devicenumber; } set { devicenumber = value; } }

        #endregion

        #region ft_program_data structure
        //
        // structure to hold program data for FT_Program function
        //
        public struct ft_program_data_struct
        {

            public UInt32 Signature1;			// Header - must be 0x00000000 
            public UInt32 Signature2;			// Header - must be 0xffffffff
            public UInt32 Version;				// Header - FT_PROGRAM_DATA version
            //          0 = original
            //          1 = FT2232C extensions
            //			2 = FT232R extensions

            public UInt16 VendorId;				// 0x0403
            public UInt16 ProductId;				// 0x6001

            // Manufacturer, ManufactureID, Description, and SerialNumber are changed
            // to int to act as dummy variables for using this structure with the EEPROM
            // read function - to simplify using C# we use only ReadEx so that we can
            // get these variables as parameters and not as members of this structure
            //public char* Manufacturer;			// "FTDI"
            //public char* ManufacturerId;		// "FT"
            //public char* Description;			// "USB HS Serial Converter"
            //public char* SerialNumber;			// "FT000001" if fixed, or NULL
            public int Manufacturer;			// "FTDI"
            public int ManufacturerId;		// "FT"
            public int Description;			// "USB HS Serial Converter"
            public int SerialNumber;			// "FT000001" if fixed, or NULL
            public UInt16 MaxPower;				// 0 < MaxPower <= 500
            public UInt16 PnP;					// 0 = disabled, 1 = enabled
            public UInt16 SelfPowered;			// 0 = bus powered, 1 = self powered
            public UInt16 RemoteWakeup;			// 0 = not capable, 1 = capable
            //
            // Rev4 extensions
            //
            public byte Rev4;					// non-zero if Rev4 chip, zero otherwise
            public byte IsoIn;				// non-zero if in endpoint is isochronous
            public byte IsoOut;				// non-zero if out endpoint is isochronous
            public byte PullDownEnable;		// non-zero if pull down enabled
            public byte SerNumEnable;			// non-zero if serial number to be used
            public byte USBVersionEnable;		// non-zero if chip uses USBVersion
            public UInt16 USBVersion;			// BCD (0x0200 => USB2)
            //
            // FT2232C extensions
            //
            byte Rev5;					// non-zero if Rev5 chip, zero otherwise
            byte IsoInA;				// non-zero if in endpoint is isochronous
            byte IsoInB;				// non-zero if in endpoint is isochronous
            byte IsoOutA;				// non-zero if out endpoint is isochronous
            byte IsoOutB;				// non-zero if out endpoint is isochronous
            byte PullDownEnable5;		// non-zero if pull down enabled
            byte SerNumEnable5;		// non-zero if serial number to be used
            byte USBVersionEnable5;	// non-zero if chip uses USBVersion
            UInt16 USBVersion5;			// BCD (0x0200 => USB2)
            byte AIsHighCurrent;		// non-zero if interface is high current
            byte BIsHighCurrent;		// non-zero if interface is high current
            byte IFAIsFifo;			// non-zero if interface is 245 FIFO
            byte IFAIsFifoTar;			// non-zero if interface is 245 FIFO CPU target
            byte IFAIsFastSer;			// non-zero if interface is Fast serial
            byte AIsVCP;				// non-zero if interface is to use VCP drivers
            byte IFBIsFifo;			// non-zero if interface is 245 FIFO
            byte IFBIsFifoTar;			// non-zero if interface is 245 FIFO CPU target
            byte IFBIsFastSer;			// non-zero if interface is Fast serial
            byte BIsVCP;				// non-zero if interface is to use VCP drivers
            //
            // FT232R extensions
            //
            public byte UseExtOsc;			// Use External Oscillator
            public byte HighDriveIOs;			// High Drive I/Os
            public byte EndpointSize;			// Endpoint size

            public byte PullDownEnableR;		// non-zero if pull down enabled
            public byte SerNumEnableR;		// non-zero if serial number to be used

            public byte InvertTXD;			// non-zero if invert TXD
            public byte InvertRXD;			// non-zero if invert RXD
            public byte InvertRTS;			// non-zero if invert RTS
            public byte InvertCTS;			// non-zero if invert CTS
            public byte InvertDTR;			// non-zero if invert DTR
            public byte InvertDSR;			// non-zero if invert DSR
            public byte InvertDCD;			// non-zero if invert DCD
            public byte InvertRI;				// non-zero if invert RI

            public byte Cbus0;				// Cbus Mux control
            public byte Cbus1;				// Cbus Mux control
            public byte Cbus2;				// Cbus Mux control
            public byte Cbus3;				// Cbus Mux control
            public byte Cbus4;				// Cbus Mux control

            public byte RIsVCP;				// non-zero if using VCP drivers

        }

        // create one instance of ft_program_data structure to expose properties
        ft_program_data_struct FT_PROGRAM_DATA = new ft_program_data_struct();

        #endregion

        #region Data Accessors for FT_PROGRAM_DATA structure
        public ushort VendorId
        {
            get
            {
                return FT_PROGRAM_DATA.VendorId;
            }
            set
            {
                FT_PROGRAM_DATA.VendorId = value;
            }
        }
        public ushort ProductId
        {
            get
            {
                return FT_PROGRAM_DATA.ProductId;
            }
            set
            {
                FT_PROGRAM_DATA.ProductId = value;
            }
        }
        public byte SerNumEnable
        {
            get
            {
                return FT_PROGRAM_DATA.SerNumEnable;
            }
            set
            {
                FT_PROGRAM_DATA.SerNumEnable = value;
            }
        }
        public byte PullDownEnabled
        {
            get
            {
                return FT_PROGRAM_DATA.PullDownEnable;
            }
            set
            {
                FT_PROGRAM_DATA.PullDownEnable = value;
            }
        }
        public UInt16 MaxPower
        {
            get
            {
                return FT_PROGRAM_DATA.MaxPower;
            }
            set
            {
                FT_PROGRAM_DATA.MaxPower = value;
            }
        }
        public UInt16 SelfPowered
        {
            get
            {
                return FT_PROGRAM_DATA.SelfPowered;
            }
            set
            {
                FT_PROGRAM_DATA.SelfPowered = value;
            }
        }
        public UInt16 USBVersion
        {
            get
            {
                return FT_PROGRAM_DATA.USBVersion;
            }
            set
            {
                FT_PROGRAM_DATA.USBVersion = value;
            }
        }
        public UInt16 RemoteWakeup
        {
            get
            {
                return FT_PROGRAM_DATA.RemoteWakeup;
            }
            set
            {
                FT_PROGRAM_DATA.RemoteWakeup = value;
            }
        }
        public byte HighDriveIOs
        {
            get
            {
                return FT_PROGRAM_DATA.HighDriveIOs;
            }
            set
            {
                FT_PROGRAM_DATA.HighDriveIOs = value;
            }
        }
        public byte RIsVCP
        {
            get
            {
                return FT_PROGRAM_DATA.RIsVCP;
            }
            set
            {
                FT_PROGRAM_DATA.RIsVCP = value;
            }
        }
        public byte Cbus0
        {
            get
            {
                return FT_PROGRAM_DATA.Cbus0;
            }
            set
            {
                FT_PROGRAM_DATA.Cbus0 = value;
            }
        }
        public byte Cbus1
        {
            get
            {
                return FT_PROGRAM_DATA.Cbus1;
            }
            set
            {
                FT_PROGRAM_DATA.Cbus1 = value;
            }
        }
        public byte Cbus2
        {
            get
            {
                return FT_PROGRAM_DATA.Cbus2;
            }
            set
            {
                FT_PROGRAM_DATA.Cbus2 = value;
            }
        }
        public byte Cbus3
        {
            get
            {
                return FT_PROGRAM_DATA.Cbus3;
            }
            set
            {
                FT_PROGRAM_DATA.Cbus3 = value;
            }
        }
        public byte Cbus4
        {
            get
            {
                return FT_PROGRAM_DATA.Cbus4;
            }
            set
            {
                FT_PROGRAM_DATA.Cbus4 = value;
            }
        }
        public byte InvertTXD
        {
            get
            {
                return FT_PROGRAM_DATA.InvertTXD;
            }
            set
            {
                FT_PROGRAM_DATA.InvertTXD = value;
            }
        }
        public byte InvertRXD
        {
            get
            {
                return FT_PROGRAM_DATA.InvertRXD;
            }
            set
            {
                FT_PROGRAM_DATA.InvertRXD = value;
            }
        }
        public byte InvertRTS
        {
            get
            {
                return FT_PROGRAM_DATA.InvertRTS;
            }
            set
            {
                FT_PROGRAM_DATA.InvertRTS = value;
            }
        }
        public byte InvertCTS
        {
            get
            {
                return FT_PROGRAM_DATA.InvertCTS;
            }
            set
            {
                FT_PROGRAM_DATA.InvertCTS = value;
            }
        }
        public byte InvertDTR
        {
            get
            {
                return FT_PROGRAM_DATA.InvertDTR;
            }
            set
            {
                FT_PROGRAM_DATA.InvertDTR = value;
            }
        }
        public byte InvertDSR
        {
            get
            {
                return FT_PROGRAM_DATA.InvertDSR;
            }
            set
            {
                FT_PROGRAM_DATA.InvertDSR = value;
            }
        }
        public byte InvertDCD
        {
            get
            {
                return FT_PROGRAM_DATA.InvertDCD;
            }
            set
            {
                FT_PROGRAM_DATA.InvertDCD = value;
            }
        }
        public byte InvertRI
        {
            get
            {
                return FT_PROGRAM_DATA.InvertRI;
            }
            set
            {
                FT_PROGRAM_DATA.InvertRI = value;
            }
        }
        #endregion

    #endregion

    #region friendly methods for DLL functions

        #region parse FT_STATUS
        public string parseFT_STATUS(FT_STATUS ftStaus)
        {
            UInt32 temp = (UInt32)ftStaus;

            string str = "NOT INITIALIZED";

            switch (temp)
            {
                case 0:
                    str = "FT_OK";
                    break;
                case 1:
                    str = "FT_INVALID_HANDLE";
                    break;
                case 2:
                    str = "FT_DEVICE_NOT_FOUND";
                    break;
                case 3:
                    str = "FT_DEVICE_NOT_OPENED";
                    break;
                case 4:
                    str = "FT_IO_ERROR";
                    break;
                case 5:
                    str = "FT_INSUFFICIENT_RESOURCES";
                    break;
                case 6:
                    str = "FT_INVALID_PARAMETER";
                    break;
                case 7:
                    str = "FT_INVALID_BAUD_RATE";
                    break;
                case 8:
                    str = "FT_DEVICE_NOT_OPENED_FOR_ERASE";
                    break;
                case 9:
                    str = "FT_DEVICE_NOT_OPENED_FOR_WRITE";
                    break;
                case 10:
                    str = "FT_FAILED_TO_WRITE_DEVICE";
                    break;
                case 11:
                    str = "FT_EEPROM_READ_FAILED";
                    break;
                case 12:
                    str = "FT_EEPROM_WRITE_FAILED";
                    break;
                case 13:
                    str = "FT_EEPROM_ERASE_FAILED";
                    break;
                case 14:
                    str = "FT_EEPROM_NOT_PRESENT";
                    break;
                case 15:
                    str = "FT_EEPROM_NOT_PROGRAMMED";
                    break;
                case 16:
                    str = "FT_INVALID_ARGS";
                    break;
                case 17:
                    str = "FT_OTHER_ERROR";
                    break;
                default:
                    str = "NUMBER NOT IN FTSTATUS ENUM";
                    break;
            }
            //MessageBox.Show("parseFT_STATUS = " + str);
            return str;
        }
        #endregion

        #region Support for the device open, close, and reset functions

        // 1. Opens a device based on a number that can be used in sequence to open
        //  multiple devices until. This number is NOT known as tied to a specific device.
        // 2. Opens a device based on the serial number.
        // 3. Opens a device based on the descriptor.
        // 4. Opens a device based on the location ID.
        public FT_STATUS openDevice(UInt32 device, ref UInt32 handle_p)
        {
            return FT_Open(device, ref handle_p);
        }

        public FT_STATUS openSerialNumber(string serialNumber, ref UInt32 handle_p)
        {
           // FT_OPEN_BY_SERIAL_NUMBER = 1
            return FT_OpenEx(serialNumber, 1, ref handle_p);
        }

        public FT_STATUS openDescription(string description, ref UInt32 handle_p)
        {
           // FT_OPEN_BY_DESCRIPTION = 2
            return FT_OpenEx(description, 2, ref handle_p);
        }

        public FT_STATUS openLocationID(UInt32 locID, ref UInt32 handle_p)
        {
           // FT_OPEN_BY_LOCATION = 4 
            return FT_OpenEx(locID, 4, ref handle_p);
        }

        public FT_STATUS closeDevice(UInt32 handle_p)
        {
            return FT_Close(handle_p);
        }

        public FT_STATUS resetDevice(UInt32 handle_p)
        {
            return FT_ResetDevice(handle_p);
        }

        public FT_STATUS cyclePort(UInt32 handle_p)
        {
            return FT_CyclePort(handle_p);
        }
        #endregion

        #region device information retrieval methods

        // friendly port of FT_CreateDeviceInfoList
        public FT_STATUS createDeviceInfoList()
        {
            return FT_CreateDeviceInfoList(ref numDevs_p);
        }

        // friendly port of FT_GetDeviceInfoDetail for device with index
        public FT_STATUS getDeviceInfoDetail(UInt32 index)
        {
            return FT_GetDeviceInfoDetail(index, ref flags_p, ref type_p, ref devicetype_p, ref locID_p, serialNumberArray, descriptionArray, ref handle_p);        
        }
        
        // friendly port of FT_GetDeviceInfo for device with opened handle
        public FT_STATUS getDeviceInfo(UInt32 handle)
        {
            UInt32 dummy = 0;
            return FT_GetDeviceInfo(handle, ref type_p, ref devicetype_p, serialNumberArray, descriptionArray, dummy);  
        }
       
        // Helper function to return a string for the device type
        // and since we are only using FT232R, we don't need this
        // but are leaving it just in case...
        public string deviceType(uint typeNum)
        {
            //based on D2XX FT_DEVICE definitions
            string[] type = {"FT_DEVICE_BM",
                             "FT_DEVICE_AM",
                             "FT_DEVICE_100AX",
                             "FT_DEVICE_UNKNOWN",
                             "FT_DEVICE_2232C",
                             "FT_DEVICE_232R"
                             };

            if (typeNum < type.Length)
                return type[typeNum];
            else
            {
                MessageBox.Show("SM_D2XX Error in DeviceType(): typeNum is too long");
                return "SM_D2XX Error in DeviceType(): typeNum is too long";
            }

        }

        #endregion

        #region EEPROM programming

        // EEPROM Programming Interface
        // The EEPROM holds 128 bytes of data, part of it is dedicated to the FTDI chip and the remaining
        // space is available for the user to store data. The space available in the user area depends on
        // the chip being used and available space can be determined with the EE_UASize function.

        #region Read EEPROM

        // Read the EEPROM data into the EEPROM data structure.
        // Read Manufacturer, ManufactureID, Description, SerialNumber into private variables
        // Data accessors access these values thru the ft_program_data structure and the variables
        public void readEEPROM(UInt32 handle)
        {
            // read the EEPROM and show data
            FT_STATUS ftStatus;

            ftStatus = FT_EE_ReadEx(handle, ref FT_PROGRAM_DATA, manufacturerArray, manufacturerIDArray, descriptionArray, serialNumberArray);

            if (ftStatus != FT_STATUS.FT_OK)
            {
                closeDevice(handle);
                MessageBox.Show("Error: SM_FT232R_ReadEEPROM() FT_ReadEx() status !ok");
                return;
            }

            closeDevice(handle);
        }
        #endregion

        #region Program EEPROM

        // This function prevents the user from writing a 0 to the VID which will permanently kill a FT232R
        // at least for Windows which will not open a device with VID = 0.
        public void programEEPROM(UInt32 handle)
        {
            FT_STATUS ftStatus;
            //SM_Support support = new SM_Support();

            FT_PROGRAM_DATA.Signature1 = 0x00000000;			// Header - must be 0x00000000 
            FT_PROGRAM_DATA.Signature2 = 0xffffffff;			// Header - must be 0xffffffff
            FT_PROGRAM_DATA.Version = 2;				// Header - FT_PROGRAM_DATA version

            // One last safety factor. Do not change the VID unless
            // you know what you are doing - if you try to set it to 0
            // this trap sets it to the FTDI vendor ID
            if (FT_PROGRAM_DATA.VendorId == 0)
            {
                FT_PROGRAM_DATA.VendorId = 0x0403;     //0x403 FTDI default
                MessageBox.Show("You tried to set the VendorID to 0 which would have killed your device - so this action was not allowed and the device was set to 0x403, FTDI's VendorId, instead.");
            }

            ftStatus = FT_EE_ProgramEx(handle, ref FT_PROGRAM_DATA, manufacturerArray, manufacturerIDArray, descriptionArray, serialNumberArray);
            if (ftStatus != FT_STATUS.FT_OK)
            {
                closeDevice(handle);
                MessageBox.Show("Error: SM_ProgramEx FT_EE_ProgramEx() status: " + ftStatus.ToString());
                return;
            }


            closeDevice(handle);
        }


        #endregion 

        #region EEPROM User Area

        public FT_STATUS readEEPROM_UA(UInt32 handle, [Out] char[] EEUAData, UInt32 DataLen, ref UInt32 BytesRead)
        {
            return FT_EE_UARead(handle, EEUAData, DataLen, ref BytesRead);
        }

        public FT_STATUS writeEEPROM_UA(UInt32 handle, [Out] char[] EEUAData, UInt32 DataLen)
        {
            return FT_EE_UAWrite(handle, EEUAData, DataLen);
        }

        public FT_STATUS getSizeEEPROM_UA(UInt32 handle, ref UInt32 EEUA_Size)
        {
            return FT_EE_UASize(handle, ref EEUA_Size);
        }

        public void readEEPROM_UA(ref char[] EEUA_Data)
        {
            UInt32 BytesRead = 0;
            UInt32 handle = 0;

            FT_STATUS ftStatus;

            uint EEUASize = getEEUASize(); 

            ftStatus = openDevice(0, ref handle);

            if (ftStatus != FT_STATUS.FT_OK)
            {
                MessageBox.Show("Error: getEEUAData() FT_Open failure.");
                return;
            }

            ftStatus = readEEPROM_UA(handle, EEUA_Data, EEUASize, ref BytesRead);
            if (ftStatus != FT_STATUS.FT_OK)
            {
                MessageBox.Show("Error: readEEUAData, FT_STATUS = " + ftStatus.ToString());
            }

            if (BytesRead != EEUASize) MessageBox.Show("Error: getEEUAData() - BytesRead != EEUZize");

            closeDevice(handle);
        }

        public bool writeEEPROM_UA(ref char[] EEUA_Data)
        {
            UInt32 handle = 0;

            uint EEUASize = getEEUASize();

            if (EEUASize > 0)
            {
                // read the EEPROM and show data
                FT_STATUS ftStatus;

                ftStatus = openDevice(0, ref handle);
                if (ftStatus != FT_STATUS.FT_OK)
                {
                    closeDevice(handle);
                    MessageBox.Show("Error: writeEEUAData() FT_Open failure.");
                    return false;
                }

                ftStatus = writeEEPROM_UA(handle, EEUA_Data, EEUASize);

                if (ftStatus != FT_STATUS.FT_OK)
                {
                    closeDevice(handle);
                    MessageBox.Show("Error: writeEEUAData() FT_EE_UAWrite failure.");
                    return false;
                }

                closeDevice(handle);
                return true;
            }
            else
            {
                MessageBox.Show("Error: writeEEUASize() EEUASize is not greater than 0");
                return false;
            }
        }

        public UInt32 getEEUASize()
        {
            UInt32 EEUA_Size = 0;
            UInt32 handle = 0;
            FT_STATUS ftStatus;

            ftStatus = openDevice(0, ref handle);

            if (ftStatus != FT_STATUS.FT_OK)
            {
                closeDevice(handle);
                MessageBox.Show("Error: getEEUASize() FT_Open failure.");
            }

            ftStatus = getSizeEEPROM_UA(handle, ref EEUA_Size);

            if (ftStatus != FT_STATUS.FT_OK)
            {
                closeDevice(handle);
                MessageBox.Show("Error: getEEUASize() FT_UASize failure.");
            }

            closeDevice(handle);

            return EEUA_Size;
        }
        #endregion

        #region Bit Banging

        // GetBitMode
        public FT_STATUS bitBang_GetBitMode(UInt32 handle, ref byte Mode)
        {
            return FT_GetBitMode(handle, ref Mode);
        }

        // SetBitMode
        public FT_STATUS bitBang_SetBitMode(UInt32 handle, byte Mask, byte Enable)
        {
            return FT_SetBitMode(handle, Mask, Enable);
        }

 
    #endregion

    #endregion    

        #region Serial functions for Windows Serial COM Port 'RS232'


        #region Read and write data

        //Read
        public FT_STATUS read(UInt32 handle, ref byte Buffer, UInt32 BytesToRead, ref UInt32 BytesReturned)
        {
            return FT_Read(handle, ref Buffer, BytesToRead, ref BytesReturned);
        }

        //Write
        public FT_STATUS write(UInt32 handle, ref byte Buffer, UInt32 BytesToWrite, ref UInt32 BytesWritten)
        {
            return FT_Read(handle, ref Buffer, BytesToWrite, ref BytesWritten);
        }

        #endregion

        #region Set Serial properties

        // SetBaudRate
        public FT_STATUS setBaudRate(UInt32 handle, UInt32 BaudRate)
        {
            return FT_SetBaudRate(handle, BaudRate);
        }

        // SetDataCharacteristics
        public FT_STATUS setDataCharacteristics(UInt32 handle, byte WordLength, byte StopBits, byte Parity)
        {
            return FT_SetDataCharacteristics(handle, WordLength, StopBits, Parity);
        }

        // SetFlowControl
        public FT_STATUS setFlowControl(FT_HANDLE handle, char FlowControl, byte Xon, byte Xoff)
        {
            return FT_SetFlowControl(handle, FlowControl, Xon, Xoff);
        }

        // SetDtr
        public FT_STATUS setDtr(UInt32 handle)
        {
            return FT_SetDtr(handle);
        }

        // ClrDtr
        public FT_STATUS clrDtr(UInt32 handle)
        {
            return FT_ClrDtr(handle);
        }

        // SetRts      
        public FT_STATUS setRts(UInt32 handle)
        {
            return FT_SetRts(handle);
        }

        // ClrRts
       public FT_STATUS clrRts(UInt32 handle)
        {
            return FT_ClrRts(handle);
        }

        // GetModemStatus
        public FT_STATUS getModeStatus(UInt32 handle, ref UInt32 ModemStatus)
        {
            return FT_GetModemStatus(handle, ref ModemStatus);
        }

        #endregion

        #region Serial Miscellaneous
        // SetChars
        public FT_STATUS setChars(FT_HANDLE handle, byte EventCh, byte EventChEn, byte ErrorCh, byte ErrorChEn)
        {
            return FT_SetChars(handle, EventCh, EventChEn, ErrorCh, ErrorChEn);
        } 

        // Purge
        public FT_STATUS purge(UInt32 handle, UInt32 Mask)
        {
            return FT_Purge(handle, Mask);
        }       
 
        // SetTimeouts
        public FT_STATUS setTimeouts(UInt32 handle, UInt32 ReadTimeout, UInt32 WriteTimeout)
        {
            return FT_SetTimeouts(handle, ReadTimeout, WriteTimeout);
        }

        // GetQueueStatus
        public FT_STATUS getQueueStatus(UInt32 handle, ref UInt32 AmountInRxQueue)
        {
            return FT_GetQueueStatus(handle, ref AmountInRxQueue);
        }

        // GetStatus
        public FT_STATUS getStatus(UInt32 handle, ref UInt32 AmountInRxQueue, ref UInt32 AmountInTxQueue, ref UInt32 EventStatus)
        {
            return FT_GetStatus(handle, ref AmountInRxQueue, ref AmountInTxQueue, ref EventStatus);
        }

        // SetBreakOn
        public FT_STATUS setBreakOn(UInt32 handle)
        {
            return FT_SetBreakOn(handle);
        }

        // SetBreakOff
        public FT_STATUS setBreakOff(UInt32 handle)
        {
            return FT_SetBreakOff(handle);
        }

        #region SetEventNotification

        //FT Notification Event Masks (See FT_SetEventNotification)
        public const UInt32 FT_EVENT_RXCHAR = 1;
        public const UInt32 FT_EVENT_MODEM_STATUS = 2;
        public const UInt32 WAIT_ABANDONED = 0x80;
        //public const UInt32 WAIT_FAILED = &HFFFFFFFF;
        public const UInt32 WAIT_OBJECT_0 = 0;
        public const UInt32 WAIT_TIMEOUT = 0x102;
        public const UInt32 INFINITE = 0xFFFFFFFF;

        public string parseNotificationEvent(UInt32 NotificationEvent)
        {
            string str = "NOT INITIALIZED";

            switch (NotificationEvent)
            {
                case FT_EVENT_RXCHAR:
                    str = "FT_EVENT_RXCHAR";
                    break;
                case FT_EVENT_MODEM_STATUS:
                    str = "FT_EVENT_MODEM_STATUS";
                    break;
                case WAIT_ABANDONED:
                    str = "WAIT_ABANDONED";
                    break;
                case WAIT_OBJECT_0:
                    str = "WAIT_OBJECT_0";
                    break;
                case WAIT_TIMEOUT:
                    str = "WAIT_TIMEOUT";
                    break;
                case INFINITE:
                    str = "INFINITE";
                    break;
                default:
                    str = "INVALID NOTIFICATION EVENT NUMBER";
                    break;
            }
            //MessageBox.Show("parseNotificaton Event = " + str);
            return str;
        }
        #endregion

        #endregion


    #endregion

    #endregion

    }
}

